package com.recipedb.recipedb.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.recipedb.recipedb.entity.RecipeDraft;
import com.recipedb.recipedb.repository.RecipeDraftRepository;
import com.recipedb.recipedb.service.RecipeDraftService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class RecipeDraftServiceImpl implements RecipeDraftService {

    @Autowired
    private RecipeDraftRepository repository;

    private final ObjectMapper objectMapper = new ObjectMapper();

    private final String draftPath = "/var/www/recipe-app/uploads/recipes/draft/";

    @Override
    public RecipeDraft save(RecipeDraft entity) {
        return repository.save(entity);
    }

    @Override
    public void deleteById(Long id) {
        repository.deleteById(id);
    }

    @Override
    public Optional<RecipeDraft> findById(Long id) {
        return repository.findById(id);
    }

    @Override
    public List<RecipeDraft> findAll() {
        return repository.findAll();
    }

    @Override
    public List<RecipeDraft> findByUserId(Long userId) {
        return repository.findByUserIdOrderByCreatedAtDesc(userId);
    }

    @Override
    public RecipeDraft updateById(Long id, RecipeDraft partialEntity) {
        RecipeDraft existingDraft = repository.findById(id)
                .orElseThrow(() -> new RuntimeException("RecipeDraft not found with id: " + id));

        if (partialEntity.getDuration() != null) existingDraft.setDuration(partialEntity.getDuration());
        if (partialEntity.getTitle() != null) existingDraft.setTitle(partialEntity.getTitle());
        if (partialEntity.getDescription() != null) existingDraft.setDescription(partialEntity.getDescription());
        if (partialEntity.getImage() != null) existingDraft.setImage(partialEntity.getImage());
        if (partialEntity.getDifficulty() != null) existingDraft.setDifficulty(partialEntity.getDifficulty());
        if (partialEntity.getServings() != null) existingDraft.setServings(partialEntity.getServings());
        if (partialEntity.getIngredientsJson() != null) existingDraft.setIngredientsJson(partialEntity.getIngredientsJson());
        if (partialEntity.getStepsJson() != null) existingDraft.setStepsJson(partialEntity.getStepsJson());
        if (partialEntity.getCategoriesJson() != null) existingDraft.setCategoriesJson(partialEntity.getCategoriesJson());
        if (partialEntity.getTagsJson() != null) existingDraft.setTagsJson(partialEntity.getTagsJson());

        return repository.save(existingDraft);
    }

    @Override
    public Page<RecipeDraft> searchDrafts(Long userId, String keyword, String tag, String category, String ingredient, Integer pageNum, Integer pageSize) {
        int page = pageNum == null || pageNum < 1 ? 0 : pageNum - 1;
        int size = pageSize == null || pageSize < 1 ? 10 : pageSize;

        List<RecipeDraft> allUserDrafts = repository.findByUserIdOrderByCreatedAtDesc(userId);
        if (allUserDrafts.isEmpty()) return new PageImpl<>(new ArrayList<>(), PageRequest.of(page, size), 0);

        List<RecipeDraft> filteredDrafts = allUserDrafts.stream()
                .filter(draft -> matchDraft(draft, keyword, tag, category, ingredient))
                .collect(Collectors.toList());

        int startIndex = page * size;
        int endIndex = Math.min(startIndex + size, filteredDrafts.size());
        List<RecipeDraft> pagedDrafts = startIndex >= filteredDrafts.size() ? new ArrayList<>() : filteredDrafts.subList(startIndex, endIndex);

        return new PageImpl<>(pagedDrafts, PageRequest.of(page, size), filteredDrafts.size());
    }

    private boolean matchDraft(RecipeDraft draft, String keyword, String tag, String category, String ingredient) {
        boolean keywordMatch = true;
        if (keyword != null && !keyword.isEmpty()) {
            String lowerKeyword = keyword.toLowerCase();
            boolean titleMatch = draft.getTitle() != null && draft.getTitle().toLowerCase().contains(lowerKeyword);
            boolean descMatch = draft.getDescription() != null && draft.getDescription().toLowerCase().contains(lowerKeyword);
            keywordMatch = titleMatch || descMatch;
        }
        if (!keywordMatch) return false;

        boolean tagMatch = true;
        if (tag != null && !tag.isEmpty()) tagMatch = isJsonFieldContain(draft.getTagsJson(), tag);
        if (!tagMatch) return false;

        boolean categoryMatch = true;
        if (category != null && !category.isEmpty()) categoryMatch = isJsonFieldContain(draft.getCategoriesJson(), category);
        if (!categoryMatch) return false;

        boolean ingredientMatch = true;
        if (ingredient != null && !ingredient.isEmpty()) ingredientMatch = isJsonFieldContain(draft.getIngredientsJson(), ingredient);
        if (!ingredientMatch) return false;

        return true;
    }

    private boolean isJsonFieldContain(String jsonStr, String target) {
        if (jsonStr == null || jsonStr.isEmpty() || target == null || target.isEmpty()) return false;
        try {
            JsonNode jsonNode = objectMapper.readTree(jsonStr);
            return jsonNode.toString().toLowerCase().contains(target.toLowerCase());
        } catch (JsonProcessingException e) {
            return false;
        }
    }

    // ---------------- 图片上传相关 ----------------

    @Override
    public String uploadDraftImage(Long draftDbId, int stepId, MultipartFile file) {
        RecipeDraft draft = repository.findById(draftDbId).orElseThrow(() -> new RuntimeException("草稿不存在: " + draftDbId));

        String draftId = draft.getImage();
        if (draftId == null || draftId.isEmpty()) {
            draftId = String.format("d%06d", draft.getId());
            draft.setImage(draftId);
            repository.save(draft);
        }

        String filename = stepId == 0 ? draftId + ".jpg" : draftId + "_0" + stepId + ".jpg";
        File target = new File(draftPath + filename);

        try {
            file.transferTo(target);
        } catch (IOException e) {
            throw new RuntimeException("上传草稿图片失败", e);
        }

        return "/uploads/recipes/draft/" + filename;
    }

    @Override
    public String getCoverUrl(RecipeDraft draft) {
        if (draft.getImage() == null || draft.getImage().isEmpty()) return null;
        return "/uploads/recipes/draft/" + draft.getImage() + ".jpg";
    }

    @Override
    public List<String> getStepUrls(RecipeDraft draft) {
        List<String> urls = new ArrayList<>();
        if (draft.getImage() == null || draft.getImage().isEmpty()) return urls;

        int stepCount = 0;
        try {
            stepCount = objectMapper.readTree(draft.getStepsJson()).size();
        } catch (Exception e) {
            stepCount = 0;
        }

        for (int i = 1; i <= stepCount; i++) {
            urls.add("/uploads/recipes/draft/" + draft.getImage() + "_0" + i + ".jpg");
        }
        return urls;
    }
}
